package com.jokerku.mini.schedule.export;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONValidator;
import com.jokerku.mini.schedule.common.Constants;
import com.jokerku.mini.schedule.domain.*;
import com.jokerku.mini.schedule.util.StrUtil;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: guzq
 * @CreateTime: 2023/05/31 14:51
 * @Description: 定时任务后台操作
 * @Version: 1.0
 */
public class DcsScheduleResource implements  IDcsScheduleResource {

    private CuratorFramework client;

    public DcsScheduleResource(String zkAddress) {
        client = CuratorFrameworkFactory.newClient(zkAddress, new RetryNTimes(10, 5000));
        client.start();
    }

    public CuratorFramework getClient() {
        return client;
    }

    /**
     * 查询所有的服务节点
     *
     * @return
     */
    @Override
    public List<String> queryPathRootServerList() throws Exception {
        return getChildren(StrUtil.join(Constants.Global.rootPath, Constants.Global.LINE, "server"));
    }

    /**
     * 查询指定服务节点下的定时任务数据
     *
     * @param schedulerServerId
     * @return
     */
    @Override
    public List<DcsScheduleInfo> queryDcsScheduleInfoList(String schedulerServerId) throws Exception {
        List<DcsScheduleInfo> dcsScheduleInfoList = new ArrayList<>();
        String pathRootServer = ZkPath.buildRootServerPath(schedulerServerId);
        String scheduleServerName = getData(pathRootServer);
        // 1.查询 ip
        List<String> ipList = queryPathRootServerIpList(schedulerServerId);
        for (String ip : ipList) {
            List<String> clazzList = queryPathRootServerIpClass(schedulerServerId, ip);
            for (String clazz : clazzList) {
                List<String> methodList = queryPathRootServerIpClassMethod(schedulerServerId, ip, clazz);
                for (String method : methodList) {
                    ExecOrder execOrder = queryExecOrder(schedulerServerId, ip, clazz, method);
                    //封装对象
                    DcsScheduleInfo dcsScheduleInfo = new DcsScheduleInfo();
                    dcsScheduleInfo.setIp(ip);
                    dcsScheduleInfo.setSchedulerServerId(schedulerServerId);
                    dcsScheduleInfo.setSchedulerServerName(scheduleServerName);
                    dcsScheduleInfo.setBeanName(clazz);
                    dcsScheduleInfo.setMethodName(method);
                    if (null != execOrder) {
                        dcsScheduleInfo.setDesc(execOrder.getDesc());
                        dcsScheduleInfo.setCron(execOrder.getCron());
                        dcsScheduleInfo.setStatus(queryStatus(schedulerServerId, ip, clazz, method) ? 1 : 0);
                    } else {
                        dcsScheduleInfo.setStatus(2);
                    }
                    dcsScheduleInfoList.add(dcsScheduleInfo);
                }
            }
        }
        return dcsScheduleInfoList;
    }

    private boolean queryStatus(String schedulerServerId, String ip, String clazz, String method) throws Exception {
        String pathRootServerIpClassMethodStatus = ZkPath.buildServerTaskClassMethodStatusPath(schedulerServerId, ip, clazz, method);
        String data = getData(pathRootServerIpClassMethodStatus);
        return "1".equals(data);
    }

    private ExecOrder queryExecOrder(String schedulerServerId, String ip, String clazz, String method) throws Exception {
        String pathRootServerIpClassMethodValue = ZkPath.buildServerTaskClassMethodValuePath(schedulerServerId, ip, clazz, method);
        if (null == client.checkExists().forPath(pathRootServerIpClassMethodValue)) {
            return null;
        }
        String data = getData(pathRootServerIpClassMethodValue);
        if (null == data || !JSONValidator.from(data).validate()) {
            return null;
        }
        return JSON.parseObject(data, ExecOrder.class);
    }


    private List<String> getChildren(String path) throws Exception {
        return client.getChildren().forPath(path);
    }

    private String getData(String path) throws Exception {
        byte[] bytes = client.getData().forPath(path);
        if (null == bytes || bytes.length <= 0) return null;
        return new String(bytes, Constants.Global.CHARSET);
    }

    private void setData(String path, String data) throws Exception {
        if (null == client.checkExists().forPath(path)) return;
        client.setData().forPath(path, data.getBytes(Constants.Global.CHARSET));
    }

    private List<String> queryPathRootServerIpList(String schedulerServerId) throws Exception {
        String pathRootServerIp = ZkPath.buildServerTaskPath(schedulerServerId);
        return getChildren(pathRootServerIp);
    }

    private List<String> queryPathRootServerIpClass(String schedulerServerId, String ip) throws Exception {
        String pathRootServerIpClass = ZkPath.buildServerTaskClassPath(schedulerServerId, ip);
        return getChildren(pathRootServerIpClass);
    }

    private List<String> queryPathRootServerIpClassMethod(String schedulerServerId, String ip, String className) throws Exception {
        String pathRootServerIpClassMethod = ZkPath.buildServerTaskClassMethodPath(schedulerServerId, ip, className);
        return getChildren(pathRootServerIpClassMethod);

    }

    @Override
    public void pushInstruct(Instruct instruct) throws Exception {
       setData(ZkPath.geExecPath(), JSON.toJSONString(instruct));
    }

    @Override
    public DataCollect queryDataCollect() throws Exception {
        List<String> serverList = queryPathRootServerList();
        AtomicInteger ipCount = new AtomicInteger(0), serverCount = new AtomicInteger(serverList.size()), beanCount = new AtomicInteger(0), methodCount = new AtomicInteger(0);
        for (String schedulerServerId : serverList) {
            List<String> ipList = queryPathRootServerIpList(schedulerServerId);
            ipCount.getAndAdd(ipList.size());
            for (String ip : ipList) {
                List<String> clazzList = queryPathRootServerIpClass(schedulerServerId, ip);
                beanCount.addAndGet(clazzList.size());
                for (String clazz : clazzList) {
                    List<String> methodList = queryPathRootServerIpClassMethod(schedulerServerId, ip, clazz);
                    methodCount.addAndGet(methodList.size());
                }
            }
        }

        return new DataCollect(ipCount.get(), serverCount.get(), beanCount.get(), methodCount.get());
    }

    @Override
    public List<DcsServerNode> queryDcsServerNodeList() throws Exception {
        List<DcsServerNode> dcsServerNodeList = new ArrayList<>();
        List<String> serverList = queryPathRootServerList();
        for (String schedulerServerId : serverList) {
            String pathRootServer = ZkPath.buildRootServerPath(schedulerServerId);
            String schedulerServerName = getData(pathRootServer);
            DcsServerNode dcsServerNode = new DcsServerNode(schedulerServerId,schedulerServerName);
            dcsServerNodeList.add(dcsServerNode);
        }
        return dcsServerNodeList;
    }
}
